﻿using System;
using NUnit.Framework;
using ScrappyDB;
using ScrappyDB.BaseClasses;
using ScrappyDB.MockData;

namespace ScrappyDB.UnitTests
{
    /// <summary>
    ///This is a test class for MockDBTest and is intended
    ///to contain all MockDBTest Unit Tests
    ///</summary>
    [TestFixture]
    public class MockDBTest
    {
        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext { get; set; }

        private static MockDB db;

        #region Additional test attributes



        //Use Setup to run code before running each test
        [SetUp]
        public void Init()
        {
            var repository = new Repository();
            db = (MockDB)repository.DB();
        }
        
        //Use TearDown to run code after each test has run
        //[TearDown()]
        //public void MyTearDown()
        //{
        //}
        //

        #endregion

        [Test]
        public void QueuedMockQueryTest()
        {
            var expected1 = new SdbCollection<TestEntity>();
            expected1.Add(new TestEntity { Id = Guid.NewGuid(), TestString = "test1" });
            expected1.Add(new TestEntity { Id = Guid.NewGuid(), TestString = "test2" });

            db.AddQueryResult(expected1);

            var expected2 = new SdbCollection<TestEntity>();
            expected2.Add(new TestEntity { Id = Guid.NewGuid(), TestString = "test3" });

            db.AddQueryResult(expected2);

            SdbCollection<TestEntity> actual1 = db.Query<TestEntity>();
            Assert.AreEqual(2, actual1.Count);
            Assert.AreEqual(expected1, actual1);

            SdbCollection<TestEntity> actual2 = db.Query<TestEntity>();
            Assert.AreEqual(1, actual2.Count);
            Assert.AreEqual(expected2, actual2);
        }

        [Test]
        public void SimpleCountTest()
        {
            int expected = 0;
            db.AddCountResult(expected);

            int actual = db.Count<TestEntity>();

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void SimpleLoadTest()
        {
            var expected = new TestEntity { Id = Guid.NewGuid(), TestString = "test1" };
            db.AddLoadResult(expected);

            string id = "meaningless in a unit test";
            var actual = db.Find<TestEntity>(id);

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void EmptyLoadTest()
        {
            try
            {
                string id = "meaningless in a unit test";
                var actual = db.Find<TestEntity>(id);
                Assert.Fail("This should have thrown a MockDbNoMockDataException exception");
            }
            catch (MockDbExceptions.MockDbNoMockDataException)
            {
                Assert.IsTrue(true);
            }
        }

        [Test]
        public void SimpleMockQueryTest()
        {
            var expected = new SdbCollection<TestEntity>
                               {
                                   new TestEntity {Id = Guid.NewGuid(), TestString = "test1"},
                                   new TestEntity {Id = Guid.NewGuid(), TestString = "test2"}
                               };
            db.AddQueryResult(expected);

            SdbCollection<TestEntity> actual = db.Query<TestEntity>();

            Assert.AreEqual(expected, actual);
        }

        [Test]
        public void SimpleSaveEntityTest()
        {
            var expected = new TestEntity { Id = Guid.Empty, TestString = "test2" };
            db.AddExpectedSaveEntityResult(expected);

            var seperateMatchingInstance = new TestEntity { Id = Guid.Empty, TestString = "test2" };

            //save will throw an exception if it fails tests
            db.SaveChanges(seperateMatchingInstance);

            Assert.IsTrue(true);
        }

        [Test]
        public void SaveEntityValueMismatchTest()
        {
            try
            {
                var expected = new TestEntity { Id = Guid.Empty, TestString = "test2" };
                db.AddExpectedSaveEntityResult(expected);

                var mismatchedInstance = new TestEntity { Id = Guid.Empty, TestString = "bad value" };

                //save will throw an exception if it fails tests
                db.SaveChanges(mismatchedInstance);

                Assert.Fail("This should have thrown a MockDbDataValueMismatchException");
            }
            catch (MockDbExceptions.MockDbDataValueMismatchException)
            {
                Assert.IsTrue(true);
            }
        }

        [Test]
        public void SaveEntityTypeMismatchTest()
        {
            try
            {
                var expected = new TestEntity { Id = Guid.Empty, TestString = "test2" };
                db.AddExpectedSaveEntityResult(expected);

                var mismatch = new TestEntity2 { Id = Guid.Empty, TestString = "foo" };

                //save will throw an exception if it fails tests
                db.SaveChanges(mismatch);
                Assert.Fail("This should have thrown a MockDbDataTypeMismatchException");
            }
            catch (MockDbExceptions.MockDbDataTypeMismatchException)
            {
                Assert.IsTrue(true);
            }
        }

        #region Nested type: TestEntity

        private class TestEntity : SdbEntity
        {
            public Guid Id { get; set; }
            public string TestString { get; set; }
        }

        private class TestEntity2 : SdbEntity
        {
            public Guid Id { get; set; }
            public string TestString { get; set; }
        }

        #endregion
    }
}